package com.e3.sysmg.security.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;

import com.e3.core.base.DAOHelper;
import com.e3.core.base.ServiceException;
import com.e3.core.base.SuperService;
import com.e3.core.cache.CacheManager;
import com.e3.sysmg.audit.log.MyLoggerFactory;
import com.e3.sysmg.security.dao.ModuleDAO;
import com.e3.sysmg.security.dao.RoleDAO;
import com.e3.sysmg.security.dao.UserDAO;
import com.e3.sysmg.security.entity.ModuleEntity;
import com.e3.sysmg.security.entity.RoleEntity;
import com.e3.sysmg.security.entity.UserEntity;
import com.e3.sysmg.security.model.ModuleModel;
import com.e3.sysmg.security.model.RoleModel;
import com.e3.sysmg.security.model.UserModel;
import com.e3.sysmg.security.model.UserStatus;
import com.e3.sysmg.security.service.SecurityService;
import com.e3.web.core.model.SuperModel;

public class SecurityServiceImpl extends SuperService implements SecurityService {
	Logger logger = MyLoggerFactory.getLogger(SecurityQueryServiceImpl.class);
	
	private ModuleDAO moduleDAO;
	
	private RoleDAO roleDAO;
	
	private UserDAO userDAO;

	private ModuleDAO getModuleDAO(){
		if(moduleDAO == null){
			moduleDAO = DAOHelper.createDAOInstance(ModuleDAO.class);
		}
		return moduleDAO;
	}
	
	private RoleDAO getRoleDAO(){
		if(roleDAO == null){
			roleDAO = DAOHelper.createDAOInstance(RoleDAO.class);
		}
		return roleDAO;
	}
	
	private UserDAO getUserDAO(){
		if(userDAO == null){
			userDAO = DAOHelper.createDAOInstance(UserDAO.class);
		}
		return userDAO;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#newModule(com.e3.sysmg.security.model.ModuleModel)
	 */
	public ModuleModel newModule(ModuleModel moduleModel) throws ServiceException{
		validateModule(moduleModel);
		checkModuleExisted(moduleModel);
		
		ModuleEntity module = moduleModelToEntity(moduleModel,null);
		getModuleDAO().persist(module);
		
		moduleModel.setId(module.getId());
		return moduleModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#modifyModule(com.e3.sysmg.security.model.ModuleModel)
	 */
	public ModuleModel modifyModule(ModuleModel moduleModel) throws ServiceException{
		
		validateModule(moduleModel);
		
		long id = moduleModel.getId();
		ModuleEntity entity = getModuleDAO().getById(ModuleEntity.class, id);
		if(entity == null){
			newModule(moduleModel);
			return moduleModel;
		}
		
		String oldCode = entity.getCode();
		if(!oldCode.equals(moduleModel.getCode())){
			checkModuleExisted(moduleModel);
		}
		
		moduleModelToEntity(moduleModel, entity);
		
		getModuleDAO().merge(entity);
		
		return moduleModel;
	}
	
	private void validateModule(ModuleModel moduleModel) throws ServiceException{
		String code = moduleModel.getCode();
		String name = moduleModel.getName();
		
		if(code==null||code.trim().length()==0
				||name==null||name.trim().length()==0){
			throw new ServiceException("请设置模块的编码和名称。");
		}
	}
	
	private void validateRole(RoleModel roleModel) throws ServiceException{
		String code = roleModel.getCode();
		
		if(code==null||code.trim().length()==0){
			throw new ServiceException("请设置角色编码。");
		}
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#checkModuleExisted(com.e3.sysmg.security.model.ModuleModel)
	 */
	public void checkModuleExisted(ModuleModel moduleModel) throws ServiceException{
		if(moduleModel==null){
			return;
		}
		
		String code = moduleModel.getCode();
		String name = moduleModel.getName();
		ModuleEntity entity = getModuleDAO().getModuleEntityByCode(code);
		if(entity != null){
			throw new ServiceException("编码为'"+code+"',名称为'"+name+"'的模块已经存在，请设置新的编码和名称。");
		}
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#checkRoleExisted(com.e3.sysmg.security.model.RoleModel)
	 */
	public void checkRoleExisted(RoleModel roleModel) throws ServiceException{
		if(roleModel == null){
			return;
		}
		
		String code = roleModel.getCode();
		RoleEntity  entity = getRoleDAO().getRoleEntityByCode(code);
		if(entity != null){
			throw new ServiceException("编码为'"+code+"'的角色已经存在，请设置新的编码。");
		}
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#deleteModules(java.util.List)
	 */
	public void deleteModules(List<ModuleModel> moduleModels) throws ServiceException{
		if(moduleModels==null||moduleModels.isEmpty()){
			return;
		}
		Long[] ids = getIds(moduleModels);
		deleteModuleByIds(ids);
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#deleteModules(java.util.List)
	 */
	public void deleteModuleByIds(Long[] moduleIds) throws ServiceException{
		if(moduleIds==null||moduleIds.length==0){
			return;
		}
		
		List<Long> delIds = getDeletedModuleIds(moduleIds);
		Long[] ids = new Long[delIds.size()];
		delIds.toArray(ids);
		getModuleDAO().deleteModuleByIds(ids);
	}
	
	private List<Long> getDeletedModuleIds(Long[] moduleIds) throws ServiceException{
		if(moduleIds==null||moduleIds.length==0){
			return null;
		}
		List<Long> ids = new ArrayList<Long>();
		for (long id : moduleIds) {
			if(!ids.contains(id)){
				ids.add(id);
			}
		}
		List<Long> childrenIds = getModuleDAO().getChildrenIds(moduleIds);
		if(childrenIds!=null&&childrenIds.size()>0){
			Long[] cIds = new Long[childrenIds.size()];
			childrenIds.toArray(cIds);
			List<Long> sids = getDeletedModuleIds(cIds);
			for (Long id : sids) {
				if(!ids.contains(id)){
					ids.add(id);
				}
			}
		}
		return ids; 
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#newRole(com.e3.sysmg.security.model.RoleModel)
	 */
	public RoleModel newRole(RoleModel roleModel) throws ServiceException{
		validateRole(roleModel);
		checkRoleExisted(roleModel);
		
		RoleEntity entity = roleModelToEntity(roleModel, null);
		getRoleDAO().persist(entity);
		
		roleModel.setId(entity.getId());
		return roleModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#modifyRole(com.e3.sysmg.security.model.RoleModel)
	 */
	public RoleModel modifyRole(RoleModel roleModel) throws ServiceException{
		if(roleModel==null){
			return roleModel;
		}
		long id = roleModel.getId();
		RoleEntity entity = getRoleDAO().getById(RoleEntity.class, id);
		if(entity==null){
			return newRole(roleModel);
		}
		
		if(!entity.getCode().equals(roleModel.getCode())){
			checkRoleExisted(roleModel);
		}
		
		roleModelToEntity(roleModel, entity);
		getRoleDAO().merge(entity);
		return roleModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#deleteRoles(java.util.List)
	 */
	public void deleteRoles(List<RoleModel> roleModels) throws ServiceException{
		if(roleModels==null||roleModels.isEmpty()){
			return;
		}
		Long[] ids = getIds(roleModels);
		getRoleDAO().deleteAllBySingleField(RoleEntity.class, "id", ids);
	}
	
	private void validateUser(UserModel userModel) throws ServiceException{
		String code = userModel.getCode();
		String password = userModel.getPassword();
		if(code==null||code.trim().length()==0
				||password==null||password.trim().length()==0){
			throw new ServiceException("请设置用户的编码和密码。");
		}
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#checkUserExisted(com.e3.sysmg.security.model.UserModel)
	 */
	public void checkUserExisted(UserModel userModel) throws ServiceException{
		if(userModel == null){
			return;
		}
		
		String code = userModel.getCode();
		UserEntity entity = getUserDAO().getUserEntityByCode(code);
		if(entity != null){
			throw new ServiceException("编码为'"+code+"'的用户已经存在，请设置新的编码。");
		}
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#newUser(com.e3.sysmg.security.model.UserModel)
	 */
	public UserModel newUser(UserModel userModel) throws ServiceException{
		validateUser(userModel);
		checkUserExisted(userModel);
		
		UserEntity entity = userModelToEntity(userModel, null);
		getUserDAO().persist(entity);
		
		userModel.setId(entity.getId());
		return userModel;
	}
	
	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#modifyUser(com.e3.sysmg.security.model.UserModel)
	 */
	public UserModel modifyUser(UserModel userModel) throws ServiceException{
		if(userModel==null){
			return userModel;
		}
		long id = userModel.getId();
		UserEntity entity = getUserDAO().getById(UserEntity.class, id);
		if(entity==null){
			return newUser(userModel);
		}
		
		if(!entity.getCode().equals(userModel.getCode())){
			checkUserExisted(userModel);
		}
		
		userModelToEntity(userModel, entity);
		getUserDAO().merge(entity);
		return userModel;
	}

	/* (non-Javadoc)
	 * @see com.e3.sysmg.security.service.ISecurityService#deleteUsers(java.util.List)
	 */
	public void deleteUsers(List<UserModel> userModels) throws ServiceException{
		if(userModels==null||userModels.isEmpty()){
			return;
		}
		Long[] ids = getIds(userModels);
		getUserDAO().deleteAllBySingleField(UserEntity.class, "id", ids);
	}
	
	private Long[] getIds(List<? extends SuperModel> models){
		if(models==null||models.isEmpty()){
			return null;
		}
		Long[] ids = new Long[models.size()];
		for(int i=0;i<models.size();i++){
			SuperModel model = models.get(i);
			ids[i] = model.getId();
		}
		return ids;
	}
	
	private UserEntity userModelToEntity(UserModel userModel,UserEntity userEntity){
		UserEntity entity = modelToEntity(UserEntity.class, userModel, userEntity);
		
		entity.setCode(userModel.getCode());
		entity.setName(userModel.getName());
		entity.setPassword(userModel.getPassword());
		Date date = userModel.getStartDate();
		date = (date==null?new Date():date);
		entity.setStartDate(date.getTime());
		
		date = userModel.getEndDate();
		entity.setEndDate(date==null?-1:date.getTime());

		String st = userModel.getStatus();
		int status = UserStatus.STATUS_NORMAL;
		if(st != null&&st.trim().length()>0){
			status = Integer.parseInt(st);
		}
		entity.setStatus(status);
		
		List<RoleModel> roles = userModel.getRoles();
		if(roles!=null&&roles.size()>0){
			List<RoleEntity> roleEntities = new ArrayList<RoleEntity>(roles.size());
			for (RoleModel roleModel : roles) {
				long roleId = roleModel.getId();
				roleEntities.add(createEntity(RoleEntity.class,roleId));
			}
			entity.setRoles(roleEntities);
		}
		
		return entity;
	}
	
	private RoleEntity roleModelToEntity(RoleModel roleModel,RoleEntity roleEntity){
		
		RoleEntity role = modelToEntity(RoleEntity.class, roleModel, roleEntity);

		role.setCode(roleModel.getCode());
		role.setName(roleModel.getName());
		role.setDescription(roleModel.getDescription());
		
		List<RoleModel> pModels = roleModel.getParentRoles();
		if(pModels!=null&&pModels.size()>0){
			List<RoleEntity> pEntities = new ArrayList<RoleEntity>(pModels.size());
			for (RoleModel rm : pModels) {
				long pId = rm.getId();
				RoleEntity pEntity = createEntity(RoleEntity.class, pId);
				pEntities.add(pEntity);
			}
			role.setParentRoles(pEntities);
		}
		
		List<ModuleModel> authedModules = roleModel.getAuthedModules();
		if(authedModules!=null&&authedModules.size()>0){
			List<ModuleEntity> mEntities = new ArrayList<ModuleEntity>(authedModules.size());
			for (ModuleModel mm : authedModules) {
				long mId = mm.getId();
				ModuleEntity mEntity = createEntity(ModuleEntity.class, mId);
				mEntities.add(mEntity);
			}
			role.setAuthedModules(mEntities);
		}
		return role;
	}
		
	private ModuleEntity moduleModelToEntity(ModuleModel moduleModel,ModuleEntity entity){
		ModuleEntity module = modelToEntity(ModuleEntity.class, moduleModel, entity);
		
		module.setCode(moduleModel.getCode());
		module.setName(moduleModel.getName());
		
		
		module.setParentId(moduleModel.getParentId());
		
		module.setPath(moduleModel.getPath());
		module.setStatus(moduleModel.getStatus());
		
		return module;
	}
}
